package com.basic.common.utils.easyExcel;

import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.write.handler.RowWriteHandler;
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
import cn.idev.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * Excel数据导出合并策略
 */
public class ExcelServeMergeStrategy implements RowWriteHandler {

    private Integer pkIndex;
    private List<Integer> needMergeColumnIndex = new ArrayList<>();
    private Integer mergeRowNum = 0;
    private Class<?> elementType;
    private int headerRowCount = 2; // 表头行数，默认为2行

    public ExcelServeMergeStrategy(Class<?> elementType) {
        this.elementType = elementType;
    }

    public ExcelServeMergeStrategy(Class<?> elementType, int headerRowCount) {
        this.elementType = elementType;
        this.headerRowCount = headerRowCount;
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        // 如果是表头行，直接返回
        if (isHead || row.getRowNum() < headerRowCount) {
            return;
        }
        Sheet sheet = writeSheetHolder.getSheet();
        if (null == pkIndex) {
            this.lazyInit(writeSheetHolder);
        }

        // 获取当前行的主键值
        Row currentRow = sheet.getRow(row.getRowNum());
        String currentPkValue = currentRow.getCell(pkIndex).getStringCellValue();

        // 获取上一行的主键值
        Row lastRow = sheet.getRow(row.getRowNum() - 1);
        String lastPkValue = lastRow.getCell(pkIndex).getStringCellValue();

        if (currentPkValue.equalsIgnoreCase(lastPkValue)) {
            mergeRowNum++;
        } else {
            if (mergeRowNum > 1) {
                for (Integer needMerIndex : needMergeColumnIndex) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(lastRow.getRowNum() - mergeRowNum + 1, lastRow.getRowNum(),
                            needMerIndex, needMerIndex);
                    sheet.addMergedRegionUnsafe(cellRangeAddress);
                }
            }
            mergeRowNum = 1; // 重置为1，因为当前行也是一个新的主键值的开始
        }

        // 处理最后一组相同主键值的行
        if (row.getRowNum() == sheet.getLastRowNum()) {
            if (mergeRowNum > 1) {
                for (Integer needMerIndex : needMergeColumnIndex) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum() - mergeRowNum + 1, row.getRowNum(),
                            needMerIndex, needMerIndex);
                    sheet.addMergedRegionUnsafe(cellRangeAddress);
                }
            }
        }
    }

    /**
     * 初始化下标
     */
    private void lazyInit(WriteSheetHolder writeSheetHolder) {

        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();

        // 获取标题行
        Row titleRow = sheet.getRow(0);
        // 获取DTO的类型
        Class<?> eleType = this.elementType;

        // 获取DTO所有的属性
        Field[] fields = eleType.getDeclaredFields();

        // 遍历所有的字段，因为是基于DTO的字段来构建excel，所以字段数 >= excel的列数
        for (Field theField : fields) {
            // 获取@ExcelProperty注解，用于获取该字段对应在excel中的列的下标
            ExcelProperty easyExcelAnno = theField.getAnnotation(ExcelProperty.class);
            // 为空,则表示该字段不需要导入到excel,直接处理下一个字段
            if (null == easyExcelAnno) {
                continue;
            }
            // 获取自定义的注解，用于合并单元格
            ExcelServeMerge serveBbMerge = theField.getAnnotation(ExcelServeMerge.class);

            // 没有@ExcelServeMerge注解的默认不合并
            if (null == serveBbMerge) {
                continue;
            }

            for (int index = 0; index < titleRow.getLastCellNum(); index++) {
                Cell theCell = titleRow.getCell(index);
                // 当配置为不需要导出时，返回的为null，这里作一下判断，防止NPE
                if (null == theCell) {
                    continue;
                }
                // 将字段和excel的表头匹配上
                if (easyExcelAnno.value()[0].equalsIgnoreCase(theCell.getStringCellValue())) {
                    if (serveBbMerge.isPk()) {
                        pkIndex = index;
                    }

                    if (serveBbMerge.needMerge()) {
                        needMergeColumnIndex.add(index);
                    }
                }
            }
        }

        // 没有指定主键，则异常
        if (null == this.pkIndex) {
            throw new IllegalStateException("使用@ExcelServeMerge注解必须指定主键");
        }
    }
}
